#ifndef _CCAPSULE3D_H_
#define _CCAPSULE3D_H_

#include "StdDefs.h"
#include "CMathFixed.h"
#include "CVector3d.h"
#include "CLineSegment3d.h"
#include "CSpace.h"
#include "CPlane.h"
#include "CSphere.h"

class CCapsule3d
{
public:
	CCapsule3d();
	CCapsule3d( fixed radius, const CLineSegment3d& cylindricalSegment );

	static boolean			Sweep( const CVector3d& c0v0, const CVector3d& c0v1, fixed r1, 
								   const CVector3d& c1v0, const CVector3d& c1v1, fixed r2,
								   const CVector3d& v1, const CVector3d& v2, fixed timeElapsed, fixed& t );

	static boolean			Sweep( const CVector3d& c0v0, const CVector3d& c0v1, fixed r1, 
								   const CVector3d& pos, fixed r2,
								   const CVector3d& v1, const CVector3d& v2, fixed& t );

	static boolean			Intersects( const CVector3d& c0v0, const CVector3d& c0v1, fixed r1, 
										const CVector3d& c1v0, const CVector3d& c1v1, fixed r2 );

	static boolean			Intersects( const CVector3d& c0v0, const CVector3d& c0v1, fixed r1, 
										const CPlane& plane );

	static boolean			Intersects( const CVector3d& c0v0, const CVector3d& c0v1, fixed r1, 
										const CVector3d& pos, fixed r2 );

	boolean					Sweep( const CCapsule3d& c, const CVector3d& v1, const CVector3d& v2, fixed timeElapsed, fixed& u ) const;
	boolean					Sweep ( const CSphere& sphere, const CVector3d& v1, const CVector3d& v2, fixed timeElapsed, fixed& u ) const;
	boolean					Intersects( const CCapsule3d &c ) const;
	boolean					Intersects( const CPlane& plane ) const;
	boolean					Intersects( const CSphere& sphere ) const;

	const CLineSegment3d&	GetCylindricalSegment() const;
	const fixed&			GetRadius() const;

private:
	fixed					m_radius;
	CLineSegment3d			m_seg;
};


inline
boolean CCapsule3d::Intersects( const CVector3d& c0v0, const CVector3d& c0v1, fixed r1, 
							  const CVector3d& c1v0, const CVector3d& c1v1, fixed r2 )
{
	CVector3d c1, c2;
	CLineSegment3d::ShortestVectorToSegment( c0v0, c0v1, c1v0, c1v1, c1, c2 );
	c1 -= c2;
	r1 += r2;
	if ( c1 * c1 < CMathFixed::Mul( r1, r1 ) )
		return TRUE;

	return FALSE;
}



inline
boolean CCapsule3d::Sweep( const CCapsule3d& c, const CVector3d& v1, const CVector3d& v2, fixed timeElapsed, fixed& t ) const
{
	return Sweep( m_seg.m_v0, m_seg.m_v1, m_radius, c.GetCylindricalSegment().m_v0, c.GetCylindricalSegment().m_v1, c.GetRadius(), v1, v2, timeElapsed, t );
}


inline
boolean CCapsule3d::Sweep( const CSphere& sphere, const CVector3d& v1, const CVector3d& v2, fixed timeElapsed, fixed& t ) const
{
	return Sweep( m_seg.m_v0, m_seg.m_v1, m_radius, sphere.m_translation, sphere.m_radius, v1, v2, t );
}


inline
boolean CCapsule3d::Intersects( const CCapsule3d &c ) const
{
	return Intersects( m_seg.m_v0, m_seg.m_v1, m_radius, c.GetCylindricalSegment().m_v0, c.GetCylindricalSegment().m_v1, c.GetRadius() );
}


inline
boolean CCapsule3d::Intersects( const CPlane &plane ) const
{
	return Intersects( m_seg.m_v0, m_seg.m_v1, m_radius, plane );
}


inline
boolean CCapsule3d::Intersects( const CSphere &sphere ) const
{
	return Intersects( m_seg.m_v0, m_seg.m_v1, m_radius, sphere.m_translation, sphere.m_radius );
}


inline
const CLineSegment3d& CCapsule3d::GetCylindricalSegment() const
{
	return m_seg;
}


inline
const fixed& CCapsule3d::GetRadius() const
{
	return m_radius;
}

#endif //_CCAPSULE3D_H_